/*
? Object.freeze()  是 JavaScript 中的一个方法，它用于冻结一个对象，使其不可更改。
? 一旦一个对象被冻结，就不能再添加、删除或修改其属性或方法。这可以帮助我们确保对象的不可变性，从而提高代码的可靠性和安全性。
? 肯定是使用defineProperty了
? **注意** freeze不会深度冻结
 */
//? 方式1 使用preventExtension
const _objectFreeze = object => {
    //? 类型判断
    if(typeof object !== 'object' || object === null) {
        throw new TypeError(`the ${object} is not a object`)
    }
    //? 拿键
    const keys = Object.getOwnPropertyNames(object)
    //? 返回所有符号属性的数组
    const symbols = Object.getOwnPropertySymbols(object)
        //? 符号属性也要加入遍历
    ;[...keys, ...symbols].forEach(key => {
        //? 使用defineProperty来冻结
        //? configurable负责不能删 writable负责不能改 Object.preventExtensions()负责不能加
        Object.defineProperty(object, key, {
            //? 不可配置
            //? 该属性的类型不能在数据属性和访问器属性之间更改，且
            //? 该属性不可被删除，且
            //? 其描述符的其他属性也不能被更改（但是，如果它是一个可写的数据描述符，则 value （与属性相关联的值）可以被更改，writable 可以更改为 false）
            configurable: false,
            //? 不可写 即不可以使用赋值运算符=更改
            writable: false,
        })
    })
    //? 防止对象在运行时被扩展，即该对象将被标记为不可扩展，并且无法添加新的属性或方法。但是，现有的属性和方法仍然可以被修改或删除(前面配置了不可写了)。
    Object.preventExtensions(object)
}
//? 方式2 使用seal
function freeze(obj) {

    if (Object.prototype.toString.call(obj) !== "[object Object]") {
        throw new TypeError(`${obj} is not a object`)
    }
    //? seal对象 不可增删配置但可以改
    Object.seal(obj)
    for (let key in obj) {
        if (obj.hasOwnProperty(key)) {
            Object.defineProperty(obj,key,{
                writable:false
            })
        }
    }
}

let obj = {
    a: 1,
    b: [1,2,3],
    c: {d: 1}
}
//? 原生freeze
Object.freeze(obj)
obj.a = 2
console.log(obj.a)
obj.c.d = 2
console.log(obj.c.d)
obj.e = 1
console.log('1',obj) //? 添加失败 很好


let obj1 = {
    a: 1,
    b: [1,2,3],
    c: {d: 1}
}
let obj2 = {
    a: 1,
    b: [1,2,3],
    c: {d: 1}
}
//? 自己写的freeze
freeze(obj1)
obj1.a = 2
console.log(obj1.a)
obj1.c.d = 2
console.log(obj1.c.d)
obj1.b[0] = 5
console.log(obj1.b[0])
obj1.e = 1
console.log('1',obj1) //? 添加失败 很好

_objectFreeze(obj2)
obj2.a = 2
console.log(obj2.a)  //? 1
obj2.c.d = 2
console.log(obj2.c.d) //? 2
obj2.b[0] = 5
console.log(obj2.b[0]) //? 5
obj2.e = 1
console.log('1',obj2) //? 添加失败 很好
